perm filename SERVO.OLD[CMS,LCS] blob
sn#468016 filedate 1979-08-17 generic text, type T, neo UTF8
00100 TITLE SERVO
00200 .INSERT ASMBL.FAI[CMS,LCS]
00300
00400 ;I/O address definitions.
00500 DAC ← 100000 ;8 bit DAC.
00600 JCR ← 120000 ;Joint control output register.
00700 ENCL ← 140000 ;Encoder mux low.
00800 ENCH ← 140001 ;Encoder mux high.
00900
01000 STKSIZ ← 377 ;Stack size.
01100 LSBENB ← 40 ;Enable LSB servo.
01200
01300 ;Zero page variables.
01400 ;Not shared.
01500
01600 DSPAT: BLOCK 2 ;Dispatch address for commands.
01700 DEFCMD: 0 ;Deferred command.
01900 SAVPOS: BLOCK 2 ;Position for deferred servo command.
02000
02100 CMDVEL: BLOCK 2 ;Commanded velocity.
02200 CURVEL: BLOCK 2 ;Current velocity.
02300 0 ;SETPT-1.
02400 SETPT: BLOCK 2 ;Current setpoint.
02500 0 ;SETINC-1.
02600 SETINC: BLOCK 2 ;Interpolating increment for setpoints.
02700 0 ;INTINC-1.
02800 INTINC: BLOCK 2 ;Interpolating increment for velocity.
03000 OLDSP: BLOCK 2 ;Last commanded setpoint, for CMDVEL.
03100 POSERR: BLOCK 2 ;Current position error.
03200 DACSIG: BLOCK 2 ;Scratch.
03300
03400 INCTR: 0 ;Count the interpolations.
03500 HSTTMR: 0 ;Count ticks between host commands.
03600
03700 LOGTMP: BLOCK 4 ;Temp for the arithmetic routines.
03800
03900 0 ;IVEL-1.
04000 IVEL: BLOCK 2 ;Interpolated velocity.
04300 VPTR: 0 ;Velocity averaging index.
04400 VELTBL: BLOCK 20;Velocity averaging table.
04500
04600 ZAPEND ← .-1 ;Clear all the above in startup.
04700
04800 TL: 0 ;Scratch for gray to binary.
04900 TH: 0
05000
05100 MTMP: BLOCK 2 ;Copy of multipilcand from shared memory.
00100 ;Shared ram.
00200 LOC 200 ;Second half of zero page.
00300
00400 ;STATUS byte bits.
00500 ; 7 6 5 4 3 2 1 0
00600 ; error check time no bad
00700 ; flag word out tick pos
00800
00900 0 ;Locked.
01000 STATUS: 0 ;Flags for the host.
01100 ;Fix STATUS and MODE words for host lockout?
01200 ;MODE byte bits.
01300 ;Bit 7 6 5 4 3 2 1 0
01400 ; servo integ lsb diag
01500 ; enlb enlb enbl enbl
01600
01700 0 ;Locked.
01800 MODE: 0 ;Mode bits from host.
01900
02000 CKWORD: BLOCK 2 ;Host I/O check/command word.
02100 CMDPOS: BLOCK 2 ;Commanded position from host.
02200
02300 ;IOCTRL byte bits.
02400 ;Bit 7 6 5 4 3 2 1 0
02500 ; in lsb integ pos
02600 ; tol enlb disabl mode
02700
02800 0 ;Locked.
02900 IOCTRL: 0 ;Copy of JCR output port.
03000
03100 CURPOS: BLOCK 2 ;Current position.
03200
03300 0 ;Locked.
03400 NINTER: 0 ;# of interpolations between position
03500 ;commands.
03600 0 ;Locked.
03700 INTSCL: 0 ;# of bits to shift setpoint dif for
03800 ;interpolating.
03900 0 ;Locked.
04000 HSTLIM: 0 ;# of clock ticks allowed between host
04100 ;commands.
04200 FRICTN: BLOCK 2 ;Viscous damping coefficient.
04300 GRAVTY: BLOCK 2 ;DC offset for gravity.
04400 POSTOL: BLOCK 2 ;Half-width of position tolerance band.
04500 INTTOL: BLOCK 2 ;Half-width of integration band.
04600 PGAIN: BLOCK 2 ;Position error gain.
04700
04720 VELERR: BLOCK 2 ;Velocity error.
04740 VSUM: BLOCK 2 ;Sum of last eight velocitys.
04800
04900 ;Start of prom.
05000 LOC 174000
05100
05200 INITBL: STATUS ↔ 0
05300
05400 NINTER ↔ =16 ;Number of interpolations default.
05500 INTSCL ↔ 4 ;Interpolating scale default.
05600
05700 HSTLIM ↔ =24 ;Ticks before host time out default.
05800
05900 377 ;End of INITBL flag.
00100 ;Power on reset.
00200 START: CLD
00300 LDXI STKSIZ ;Setup stack.
00400 TXS
00500
00600 LDAI 0
00700 LDXI ZAPEND
00800 RLOOP: STAZX 0 ;Reset ram.
00900 DEX
01000 BPL RLOOP
01100 STA DAC ;Clear DAC.
01200 LDXI 370 ;-8.
01300 ZSR: STAZX FRICTN+10 ;Clear shared ram.
01400 INX
01500 BMI ZSR
01600
01700 LDXI 13 ;13,,100 is 40013 is 1.0.
01800 LDYI 100
01900 STXZ PGAIN ;Reset PGAIN to 1.
02000 STYZ PGAIN+1 ;Unlock.
02100 LDXI 13 ;13,,275 is 136413 is -0.125.
02200 LDYI 275
02300 STXZ FRICTN ;Reset velocity gain to 1.
02400 STYZ FRICTN+1;Unlock.
02500
02600 TAY ;Y ← 0.
02700 BEQ RSTDEF ;Jump
02800 DLOOP: INY
02900 LDAY INITBL ;Init ram.
03000 STAZX 0
03100 INY
03200 RSTDEF: LDXY INITBL
03300 CPXI 377
03400 BNE DLOOP
03500
03600 STOP: SEI ;Go into stop mode.
03700 JSR GETPOS ;Read encoder and convert to binary.
03800 ;Sets the current position to the converted encoder value, the
03900 ;setpoint the same, clears the setpoint interpolating increment,
04000 ;and goes into stop mode.
04100 STAZ CURPOS ;Set the current position.
04200 STXZ CURPOS+1;Unlock.
04300 STAZ SETPT ;Set the setpoint.
04400 STXZ SETPT+1
04500 STAZ OLDSP ;For CMDVEL.
04600 STXZ OLDSP+1
04700 LDAI 71 ;Reset I/O control bits. Position mode off.
04800 STAZ IOCTRL
04900 STA JCR
05000
05100 LDAI 0
05200 STAZ MODE ;Clear position servo enable, etc..
05300 STAZ DEFCMD ;Clear the deferred command flag.
05400 STAZ SETPT-1 ;Clear the setpoint extension
05500 STAZ SETINC-1;and the interpolator.
05600 STAZ SETINC
05700 STAZ SETINC+1
00100 LDXI 23
00200 CLRVEL: STAZX IVEL-1 ;Clear velocity values.
00300 DEX
00400 BPL CLRVEL
00420
00440 STAZ VELERR ;Clear velocity error and sum.
00460 STAZ VELERR+1;Unlock.
00480 STAZ VSUM ;Lock.
00490 STAZ VSUM+1 ;Unlock.
00500 CLI ;End of reset.
00600
00700 RSTCKW: LDAI 377 ;Reset check word.
00800 LDXI 0
00900 SEI
01000 STAZ CKWORD ;Lock.
01100 STXZ CKWORD+1;Unlock.
01200 CLI
01300 ;Idle loop. Wait for command.
01400 IDLE: LDAZ CKWORD+1;Check for new check word.
01500 BEQ IDLE ;Not equal if bit 7 is complement of low byte.
01600
01700 SEC
01800 SEI
01900 ADCZ CKWORD ;Lock.
02000 LDXZ CKWORD+1;Unlock.
02100 CLI
02200 TAY
02300 BNE CKWDER ;Check word error.
02400 ;Check here for immediate or deferred.
02500 TXA ;Check for valid command.
02600 ORAI 3 ;3 for two commands and bit 0 = 0.
02700 ADCI 0 ;Carry = 1.
02800 BNE CKWDER ;Not a valid command.
02900
02920 ;Valid host command.
02940 LDAZ HSTLIM ;Reset host timer.
02960 STAZ HSTTMR
03000 LDAZ DEFCMD ;Check if no TICK?
03100 BNE NOTICK ;No response since last deferred command.
03200
03250 ;Check here if posiition command?
03300 SEI
03400 LDYZ CMDPOS ;Read position for servo command.
03500 LDAZ CMDPOS+1;Unlock.
03600 CLI
03700
03800 STYZ SAVPOS ;Save it for later.
03900 STAZ SAVPOS+1
04000 ASLA ;Check for valid position.
04100 BCS CSET
04200 BMI BADPOS
04300 BPL GOODP ;Jump.
04400 CSET: BPL BADPOS
04500
04600 GOODP: STXZ DEFCMD ;Save deferred command pointer.
04700
04800 JMP RSTCKW ;Handshake with host via CKWORD.
04900
05000 CKWDER: LDAI 300 ;Set check word error flag.
05100 WSTAT: ORAZ STATUS
05200 STAZ STATUS
05300 JMP STOP
05400
05500 NOTICK: LDAI 220 ;Set tick error flag.
05600 BNE WSTAT ;Jump.
05700
05800 BADPOS: LDAI 210 ;Set bad position error flag.
05900 BNE WSTAT ;Jump.
00100 ;Clock tick interrupt.
00200 TICK: PHA ;Save state.
00300 TXA
00400 PHA
00500 TYA
00600 PHA
00700
00800 INCZ IOCTRL ;Turn on interrupt flag bit.
00900 LDAZ IOCTRL ;This is only for timing checks.
01000 STA JCR ;Can be flushed.
01100
01200 JSR GETPOS ;Read position and convert to binary.
01300 SEC
01400 SBCZ CURPOS ;Subtract the old position
01500 STAZ CURVEL ;yielding the velocity.
01600 TXA ;High byte of binary position.
01700 SBCZ CURPOS+1;Unlock.
01800 STAZ CURVEL+1
01900
02000 STYZ CURPOS ;Update the current position.
02100 STXZ CURPOS+1;Unlock.
02200 DECZ HSTTMR ;Count the ticks since the last command
02300 BPL HOSTOK ;and check for timeout.
02400
02500 LDAI 0 ;Host dead. Stop.
02600 STAZ HSTTMR
02900 STAZ INTINC-1
03000 STAZ INTINC
03100 STAZ INTINC+1
03200 LDAI 240 ;Set host time out flag
03300 ORAZ STATUS
03400 STAZ STATUS
03500
03600 LDAI 20 ;Check for diagnostic enable.
03700 BITZ MODE
03800 BNE HOSTOK ;If diagnostics, then servo anyway.
03900
04000 LDAI 177 ;Turn off servo enable.
04100 ANDZ MODE
04200 STAZ MODE
04300
04400 HOSTOK: BITZ MODE ;Check if servo is enabled.
04500 BMI INTVEL
04900 JMP CURSRV ;don't servo.
05000
05100 INTVEL: CLC ;Interpolate the velocity.
05200 LDAZ IVEL-1
05300 ADCZ INTINC-1;IVEL ← IVEL + INTINC.
05400 STAZ IVEL-1
05500 LDAZ IVEL
05600 ADCZ INTINC
05700 STAZ IVEL
05800 LDAZ IVEL+1
05900 ADCZ INTINC+1
06000 STAZ IVEL+1
00100 ;Interpolate the setpoints.
00200 INTRS: CLC
00300 LDAZ SETPT-1
00400 ADCZ SETINC-1;Add the increment to the setpoint.
00500 STAZ SETPT-1
00600 LDAZ SETPT
00700 ADCZ SETINC
00800 STAZ SETPT
00900 LDAZ SETPT+1
01000 ADCZ SETINC+1
01100 STAZ SETPT+1
01200
01300 DECZ INCTR ;Check if this is the last interpolation.
01400 BNE GPOSER
01500
01600 LDAI 0 ;Clear SETINC if done interpolating.
01700 STAZ SETINC-1
01800 STAZ SETINC
01900 STAZ SETINC+1
02000 STAZ INTINC-1;Clear INTINC (commanded velocity).
02100 STAZ INTINC
02200 STAZ INTINC+1
02300
02400 ;Calculate the position error.
02500 GPOSER: SEC
02600 LDAZ CURPOS ;POSERR ← CURPOS - SETPT.
02700 SBCZ SETPT
02800 STAZ POSERR
02900 LDAZ CURPOS+1;Unlock.
03000 SBCZ SETPT+1
03100 STAZ POSERR+1
00100 BITZ MODE ;If servo is disabled, we're
00200 BPL OOTOL ;automatically out of tolerance
00300
00400 LDAZ POSERR+1;Test the sign of pos error.
00500 BMI NEGPER
00600
00700 LDAZ POSTOL ;Positive. Compare with tol.
00800 CMPZ POSERR
00900 LDAZ POSTOL+1;Unlock.
01000 SBCZ POSERR+1
01100 BCS TOLOK ;In tolerance.
01200 BCC OOTOL ;Jump.
01300
01400 NEGPER: CLC ;Negative. Add the tolerance.
01500 LDAZ POSTOL ;Lock.
01600 ADCZ POSERR
01700 LDAZ POSTOL+1;Unlock.
01800 ADCZ POSERR+1
01900 BCS TOLOK ;In tolerance.
02000
02100 OOTOL: LDAZ IOCTRL ;Out of tolerance.
02200 ANDI 177 ;Turn off the in tolerance
02300 BNE WCNTRL ;indicator. Jump.
02400
02500 TOLOK: LDAZ IOCTRL ;In tolerance. Turn it on.
02600 ORAI 200
02700 WCNTRL: STAZ IOCTRL
02800 STA JCR ;Copy it to output.
02900
03000 BITZ MODE ;If intergration is disabled,
03100 BVC OOBAND ;turn it off.
03200 LDAZ POSERR+1;Test sign of position error.
03300 BMI ADTOL
03400
03500 LDAZ INTTOL ;Positive. Compare with tol.
03600 CMPZ POSERR
03700 LDAZ INTTOL+1;Unlock.
03800 SBCZ POSERR+1
03900 BCS INBAND ;In band. Turn on integrator.
04000 BCC OOBAND ;Jump.
04100
04200 ADTOL: CLC ;Negative. Add the tolerance.
04300 LDAZ INTTOL ;Lock.
04400 ADCZ POSERR
04500 LDAZ INTTOL+1;Unlock.
04600 ADCZ POSERR+1
04700 BCS INBAND ;Check if in band.
04800
04900 OOBAND: LDAZ IOCTRL ;Out of band. Turn off
05000 ORAI 10 ;integration by setting the
05100 ANDI 357 ;control bit. LSB servo off.
05200 BNE WCTRL2 ;Jump.
00100 INBAND: LDAI LSBENB ;In band. Is LSB servo enabled?
00200 BITZ MODE
00300 BEQ RCNTRL
00400 LDAZ POSERR ;Yes. Is the error exactly 0?
00500 ORAZ POSERR+1
00600 BNE RCNTRL
00700
00800 LDAZ IOCTRL ;It is. Integration off, LSB
00900 ORAI 30 ;servo on.
01000 BNE WCTRL2 ;Jump.
01100
01200 RCNTRL: LDAZ IOCTRL ;LSB disabled or error not zero.
01300 ANDI 347 ;LSB servo off, integration on.
01400 WCTRL2: STAZ IOCTRL
01500 STA JCR ;Output it.
01600
01700 LDXZ PGAIN ;Copy position gain for multiply.
01800 LDYZ PGAIN+1 ;Unlock.
01900 STXZ MTMP
02000 STYZ MTMP+1
02100 LDYZ POSERR
02200 LDAZ POSERR+1
02300 JSR LOG ;Float the position error.
02400 LDXI MTMP ;Point X to copy of PGAIN.
02500 JSR MULTIP ;POSERR ← POSERR * PGAIN.
02600 JSR EXP ;Fix it.
02700 STYZ POSERR
02800 STAZ POSERR+1
02900
03000 ;Get the velocity error.
03100 CLC
03200 LDAZ VSUM ;Lock.
03300 ADCZ CURVEL ;VSUM ← VSUM + CURVEL.
03400 TAX
03500 LDAZ VSUM+1 ;Unlock.
03600 ADCZ CURVEL+1
03700 TAY
03800 TXA
03900 LDXZ VPTR ;Get velocity averaging index.
04000 SEC
04100 SBCZX VELTBL ;VSUM ← VSUM - VELTBL[VPTR].
04200 STAZ VSUM ;Lock.
04300 TYA
04400 SBCZX VELTBL+10
04500 STAZ VSUM+1 ;Unlock.
04600
04700 LDAZ CURVEL ;VELTBL[VPTR] ← CURVEL.
04800 STAZX VELTBL
04900 LDAZ CURVEL+1
05000 STAZX VELTBL+10
05100 INX ;VPTR ← (VPTR + 1) .AND. (VTLEN - 1).
05200 TXA
05300 ANDI 7
05400 STAZ VPTR
05500
05600 SEC
05700 LDAZ VSUM ;Lock.
05750 LDXZ VSUM+1 ;Unlock.
05800 SBCZ IVEL ;VELERR ← VSUM - IVEL.
05850 TAY ;Save VELERR.
05900 STAZ VELERR ;Lock.
06000 TXA ;Get VSUM+1.
06100 SBCZ IVEL+1
06200 STAZ VELERR+1;Unlock.
00100 JSR LOG ;Float the velocity error.
00200 STYZ MTMP ;Save the F.P. VELERR.
00300 STAZ MTMP+1
00600 LDYZ FRICTN ;Get the velocity gain (FRICTN).
00700 LDAZ FRICTN+1;Unlock.
00800 LDXI MTMP ;multiply by the velocity error,
00900 JSR MULTIP ;VELERR * VGAIN.
01000 JSR EXP
01100
01200 TAX ;Save high byte.
01300 TYA ;Get low byte.
01400 CLC ;add the position error...
01500 ADCZ POSERR
01600 TAY ;Save low byte.
01700 TXA
01800 ADCZ POSERR+1
01900 STAZ DACSIG+1
02000
02100 CLC ;...and the gravity offset.
02200 TYA ;Get the low byte.
02300 ADCZ GRAVTY ;Lock.
02400 TAY ;Save low byte.
02500 LDAZ GRAVTY+1;Unlock.
02600 ADCZ DACSIG+1
02700
02800 JSR PUTDAC ;Put result out to the DAC.
02900
03000 CMDSP: LDAZ DEFCMD ;Check for a command.
03100 BEQ INTXIT
03200 ANDI 2 ;Low nibble command bit.
03300 TAX
03400 LDAX CMDTBL ;Get command address.
03500 STAZ DSPAT
03600 LDAX CMDTBL+1
03700 STAZ DSPAT+1
03800 JMPIN DSPAT ;Execute command.
03900
04000 CMDEND: LDAI 0 ;Done with deferred command.
04100 STAZ DEFCMD ;Reset command word.
04200 INTXIT: DECZ IOCTRL ;Turn off interrupt flag.
04300 LDAZ IOCTRL ;Can be flushed.
04400 STA JCR
04500 PLA ;Restore state and dismiss interrupt.
04600 TAY
04700 PLA
04800 TAX
04900 PLA
05000 RTI
05100
05200 CMDTBL: ;DEFERRED COMMAND TABLE.
05300 CMDEND∧377 ;Nop.
05400 (CMDEND⊗-10)∧377
05500 CMDSRV∧377 ;Servo command.
05600 (CMDSRV⊗-10)∧377
00100 ;Deferred commands.
00200 CMDSRV: LDAZ MODE ;Servo command.
00300 BMI ENBLD ;Test for servo enabled.
00400 JMP CMDEND ;No. End this command.
00500
00600 ENBLD: LDAZ SAVPOS ;Enabled. Get commanded position.
00700 SEC
00800 SBCZ SETPT ;Get difference between next position
00900 STAZ SETINC ;and the last setpoint.
01000 LDAZ SAVPOS+1
01100 SBCZ SETPT+1
01200 LDXI 0
01300 STXZ SETPT-1 ;Clear setpoint and increment extentions.
01400 STXZ SETINC-1
01500 STXZ INTINC-1
01600 LDXZ INTSCL
01700 ;A = SETINC+1.
01800 SCAL: CMPI 200 ;Extend sign.
01900 RORA ;Divide the difference by the number of interpolations.
02000 RORZ SETINC
02100 RORZ SETINC-1
02200 DEX
02300 BNE SCAL
02400 STAZ SETINC+1;Which yields the interpolating increment.
02500
02600 LDAZ NINTER
02700 STAZ INCTR ;Setup the interpolator count.
02800 SEC ;INTINC ← ((CMDVEL / 2) - IVEL) / 16.
02900 LDAZ SAVPOS
03000 SBCZ OLDSP ;CMDVEL ← CMDPOS - OLDSP.
03100 STAZ CMDVEL
03200 LDAZ SAVPOS+1
03300 SBCZ OLDSP+1
03350 CMPI 200 ;Extend sign and divide by 2.
03375 RORA
03387 RORZ CMDVEL
03393 RORZ INTINC-1;INTINC = LSB of CMDVEL.
03400 STAZ CMDVEL+1
03500 LDAZ SAVPOS
03600 STAZ OLDSP ;OLDSP ← CMDPOS.
03700 LDAZ SAVPOS+1
03800 STAZ OLDSP+1
03900
04100 SEC
04200 LDAZ INTINC-1;INTINC-1 = CMDVEL-1.
04300 SBCZ IVEL-1 ;INTINC ← CMDVEL - IVEL.
04400 STAZ INTINC-1
04420 LDAZ CMDVEL
04440 SBCZ IVEL
04460 STAZ INTINC
04500 LDAZ CMDVEL+1
04600 SBCZ IVEL+1
04650 LDXZ INTSCL ;A = INTINC+1.
04700 ISCAL: CMPI 200 ;Extend sign and divide by the number of
04800 RORA ;interpolations.
04900 RORZ INTINC
05000 RORZ INTINC-1
05050 DEX
05075 BNE ISCAL
05100 STAZ INTINC+1
00100 LDAI 44
00200 ORAZ IOCTRL ;Turn on servo and current mode enable bits.
00300 STAZ IOCTRL
00400 STA JCR ;Output it.
00700 JMP CMDEND
00800
00900 ;Free mode.
01000 CURSRV: LDAI 0 ;Not servoing ("Current mode")...
01100 STA DAC ;Turn off the servo valve.
01200 STAZ SETPT-1 ;Make the setpoint track
01300 LDAZ CURPOS ;the current position in order to
01400 STAZ SETPT ;keep the arm from twitching when
01500 LDAZ CURPOS+1;the host enables the servo. Unlock.
01600 STAZ SETPT+1
01700 LDAI 373
01800 ANDZ IOCTRL ;Turn off position mode bit.
01900 STAZ IOCTRL
02000 STA JCR
02100 JMP CMDSP ;Go check on commands.
02200
02300 ;DAC output subroutine.
02400 ;Enter with 2 byte value in Y (low), A (high).
02500 ;Clobbers all registers, but the 8 bits the DAC got are returned in A.
02600 PUTDAC: BMI NEGDAC ;Assuming the last inst. loaded A.
02700 CPYI 200 ;Positive. Compare with 2↑7.
02800 SBCI 0
02900 BCC INRNGE
03000
03100 TOOHI: LDYI 177 ;Too high. Saturate positive.
03200 BNE INRNGE ;Jump.
03300
03400 NEGDAC: CPYI 200 ;Negative. Compare with -2↑7.
03500 SBCI 377
03600 BCS INRNGE
03700
03800 TOOLOW: LDYI 200 ;Too low. Saturate to -2↑7.
03900
04000 INRNGE: LDAY VETBL ;Straighting it.
04100 STA DAC ;Output 8 bits to the DAC.
04200 RTS
00100 ;Position conversion routine.
00200 GETPOS: LDY ENCL ;Read encoder.
00300 LDA ENCH
00400 ;Convert from gray to binary.
00500 STAZ TH
00600 LSRA ;Shift by 1.
00700 EORZ TH
00800 STAZ TH
00900 TAX ;X ← high byte.
01000
01100 TYA
01200 STAZ TL
01300 RORA
01400 EORZ TL
01500 STAZ TL
01600
01700 LSRZ TH ;Shift by 2.
01800 RORA
01900 LSRZ TH
02000 RORA
02100 EORZ TL
02200 STAZ TL
02300 TAY ;Y ← low byte.
02400
02500 TXA ;Get high byte.
02600 EORZ TH
02700 STAZ TH
02800
02900 LSRA ;Shift by 4.
03000 RORZ TL
03100 LSRA
03200 RORZ TL
03300 LSRA
03400 RORZ TL
03500 LSRA
03600 RORZ TL
03700
03800 EORZ TH
03900 STAZ TH
04000 TYA
04100 EORZ TL
04200 EORZ TH ;Shift by 8.
04300 TAY ;Save low byte.
04400
04500 LDXZ TH ;Get high byte.
04600 BITZ TH
04700 BVC POS ;Check if negative.
04800 TXA
04900 ORAI 200 ;Extend sign.
05000 TAX
05100
05200 POS: TYA ;Returns with position in A, Y (low) and X (high).
05300 RTS
00100 ;Arithmetic routines.
00200 ;Enter with high byte in A, low in Y.
00300 ;Returns A = characteristic and sign, Y = mantissa.
00400 ;Clobbers X, LOGTMP, LOGTMP+1.
00500 LOG: STYZ LOGTMP ;Save the inputs.
00600 STAZ LOGTMP+1
00700
00800 LDXI 20+100 ;Init characteristic to 15.
00900 CMPI 0 ;Test sign of input.
01000 BPL POSIN
01100 SEC ;Negative. 2's complement it.
01200 LDAI 0
01300 SBCZ LOGTMP
01400 STAZ LOGTMP
01500 LDAI 0
01600 SBCZ LOGTMP+1
01700 POSIN: BNE NORML ;Is high byte zero?
01800 LDAZ LOGTMP ;Yes. Low byte?
01900 BEQ RTRN ;If so, return zero.
02000 LDYI 0 ;Low nonzero. Shift left one
02100 STYZ LOGTMP ;byte,
02200 LDXI 10+100 ;change characteristic to 7.
02300 NORML: DEX ;Normalize the number, counting the
02400 ASLZ LOGTMP ;characteristic down. When the
02500 ROLA ;first "1" shifts out, we've subtracted
02600 BCC NORML ;1 from the normalized number
02700 ASLZ LOGTMP ;(This rounds the result)
02800 ADCI =11 ;and are left with the fraction
02900 TAY ;Adding 11 to that is equivalent to
03000 TXA ;adding 0.043.
03100 ADCI 0 ;Propagate the carry into the
03200 ;characteristic.
03300 ASLA ;Insert the sign bit from the saved
03400 ASLZ LOGTMP+1;input.
03500 RORA
03600 RTRN: RTS ;Done.
03700
03800 ;Enter with sign and characteristic in A, mantissa in Y
03900 ;Returns 16-bit integer, low byte in Y, high in A.
04000 ;Clobbers X, LOGTMP, LOGTMP+1.
04100 EXP: STAZ LOGTMP+1;Save sign of input.
04200 ANDI 177 ;Mask it off.
04300 BEQ ZEROIN ;Zero characteristic returns
04400 TAX ;zero.
04500 TYA ;Get the mantissa...
04600 SEC
04700 SBCI =11 ;...subtract 0.043...
04800 STAZ LOGTMP ;(save this value)
04900 TXA ;...propagate the carry and get rid
05000 SBCI 100 ;of the XS-64 offset.
05100 BMI NEGIN ;If negative (value < 1.0)
05200 ;return zero.
05300 CMPI =15 ;Test for overflow (value>=2↑15
05400 BCS SATUR
05500 TAX ;...no. Number is in range.
05600 ADCI 370 ;Is characteristic below 8?
05700 BMI BLOATE
05800 TAX ;No. Reduce if by 8,
05900 JSR UNNORM ;unnormalize.
06000 BMI GETTMP ;Jump.
00100 BLOATE: JSR UNNORM ;Yes. Unnormalize, then
00200 ASLZ LOGTMP ;(round result)
00300 ADCI 0
00400 STAZ LOGTMP ;use result as low byte and
00500 LDAI 0 ;set high byte to zero.
00600
00700 GETTMP: LDYZ LOGTMP
00800 GTMP1: LDXZ LOGTMP+1;Test sign of input...
00900 BPL POSIGN
01000 STAZ LOGTMP+1;...negative. 2's complement
01100 LDAI 0 ;the result.
01200 SEC
01300 SBCZ LOGTMP
01400 TAY
01500 LDAI 0
01600 SBCZ LOGTMP+1
01700 POSIGN: RTS
01800
01900 NEGIN: LDAI 0 ;Set the result to zero if the
02000 ZEROIN: TAY ;input is negative.
02100 RTS
02200
02300 SATUR: LDYI 377 ;Saturate result to 2↑15 - 1 if
02400 STYZ LOGTMP ;input was 15 or more.
02500 LDAI 177
02600 BNE GTMP1 ;Jump.
02700
02800 UNNORM: LDAI 1 ;Unnormalize subroutine. Add 1
02900 BNE DECRX ;to the fraction. Jump.
03000
03100 SCALE: ASLZ LOGTMP ;Scale the fraction left by the
03200 ROLA ;amount of the characteristic.
03300 DECRX: DEX
03400 BPL SCALE
03500 RTS
00100 ;Enter with characteristic of multiplier in A,
00200 ;mantissa in Y, X pointing to a pair of base page
00300 ;locations containing the multiplicand (mantissa in the
00400 ;low byte).
00500 ;Returns the product in A and Y, same form as the
00600 ;multiplier. Leaves X unchanged. Clobbers LOGTMP and
00700 ;LOGTMP+1.
00800 MULTIP: PHA
00900 EORZX 1 ;Compute sign of result,
01000 STAZ LOGTMP+1 ;save it away.
01100 PLA
01200 ANDI 177 ;Mask off multiplier sign.
01300 BEQ ZEROIN ;If zero, return zero.
01400 STAZ LOGTMP
01500 TYA ;Add the two logarithms.
01600 CLC
01700 ADCZX 0
01800 TAY
01900 LDAZX 1
02000 ANDI 177 ;If multiplicand is zero,
02100 BEQ ZEROIN ;return a zero.
02200 ADCZ LOGTMP
02300 SEC
02400 SBCI 100 ;Correct the XS-64 offset.
02500 BPL INSIGN ;Result in range?
02600 ANDI 100 ;No. If underflow,
02700 BNE NEGIN ;return zero.
02800 LDAI 177 ;Overflow. Saturate to
02900 LDYI 377 ;highest magnitude.
03000
03100 INSIGN: ASLA ;Insert the sign of the result.
03200 ASLZ LOGTMP+1
03300 RORA
03400 RTS
03500
03600 ;Inverse function: 2's complement the magnitude part
03700 ;of a 15-bit logarithm.
03800 ;Enter with characteristic in A, mantissa in Y.
03900 ;Returns inverse in the same form. X unchanged.
04000 ;Clobbers LOGTMP and LOGTMP+1.
04100 INV: STYZ LOGTMP ;Pretty straightforward...
04200 STAZ LOGTMP+1
04300 SEC
04400 LDAI 0 ;Complement the number by
04500 SBCZ LOGTMP ;subtracting it from zero.
04600 TAY
04700 LDAI 0
04800 SBCZ LOGTMP+1
04900 JMP INSIGN ;Insert the original sign.
00100 ;DAC output table.
00200 LOC (.∨377)+1 ;For start of next page.
00300 VETBL: ;DAC output table.
00400 0 ↔ 20 ↔ 26 ↔ 33 ↔ 37 ↔ 43 ↔ 46 ↔ 50
00500 52 ↔ 54 ↔ 56 ↔ 57 ↔ 60 ↔ 62 ↔ 63 ↔ 64
00600 65 ↔ 66 ↔ 67 ↔ 70 ↔ 71 ↔ 72 ↔ 73 ↔ 74
00700 75 ↔ 76 ↔ 76 ↔ 77 ↔ 100 ↔ 101 ↔ 102 ↔ 103
00800 104 ↔ 104 ↔ 105 ↔ 106 ↔ 107 ↔ 107 ↔ 110 ↔ 111
00900 112 ↔ 112 ↔ 113 ↔ 114 ↔ 115 ↔ 115 ↔ 116 ↔ 117
01000 117 ↔ 120 ↔ 121 ↔ 121 ↔ 122 ↔ 123 ↔ 124 ↔ 124
01100 125 ↔ 126 ↔ 127 ↔ 127 ↔ 130 ↔ 131 ↔ 131 ↔ 132
01200 133 ↔ 133 ↔ 134 ↔ 135 ↔ 135 ↔ 136 ↔ 136 ↔ 137
01300 140 ↔ 140 ↔ 141 ↔ 142 ↔ 142 ↔ 143 ↔ 143 ↔ 144
01400 145 ↔ 145 ↔ 146 ↔ 146 ↔ 147 ↔ 150 ↔ 150 ↔ 151
01500 151 ↔ 152 ↔ 153 ↔ 153 ↔ 154 ↔ 154 ↔ 155 ↔ 156
01600 156 ↔ 157 ↔ 160 ↔ 160 ↔ 161 ↔ 161 ↔ 162 ↔ 162
01700 163 ↔ 164 ↔ 164 ↔ 165 ↔ 165 ↔ 166 ↔ 166 ↔ 167
01800 167 ↔ 170 ↔ 170 ↔ 171 ↔ 171 ↔ 172 ↔ 172 ↔ 173
01900 173 ↔ 174 ↔ 174 ↔ 175 ↔ 176 ↔ 176 ↔ 177 ↔ 177
02000
02100 200 ↔ 200 ↔ 200 ↔ 201 ↔ 201 ↔ 202 ↔ 203 ↔ 203
02200 204 ↔ 204 ↔ 205 ↔ 205 ↔ 206 ↔ 206 ↔ 207 ↔ 207
02300 210 ↔ 210 ↔ 211 ↔ 211 ↔ 212 ↔ 212 ↔ 213 ↔ 213
02400 214 ↔ 215 ↔ 215 ↔ 216 ↔ 216 ↔ 217 ↔ 217 ↔ 220
02500 221 ↔ 221 ↔ 222 ↔ 223 ↔ 223 ↔ 224 ↔ 224 ↔ 225
02600 226 ↔ 226 ↔ 227 ↔ 227 ↔ 230 ↔ 231 ↔ 231 ↔ 232
02700 232 ↔ 233 ↔ 234 ↔ 234 ↔ 235 ↔ 235 ↔ 236 ↔ 237
02800 237 ↔ 240 ↔ 241 ↔ 241 ↔ 242 ↔ 242 ↔ 243 ↔ 244
02900 244 ↔ 245 ↔ 246 ↔ 246 ↔ 247 ↔ 250 ↔ 250 ↔ 251
03000 252 ↔ 253 ↔ 253 ↔ 254 ↔ 255 ↔ 256 ↔ 256 ↔ 257
03100 260 ↔ 260 ↔ 261 ↔ 262 ↔ 262 ↔ 263 ↔ 264 ↔ 265
03200 265 ↔ 266 ↔ 267 ↔ 270 ↔ 270 ↔ 271 ↔ 272 ↔ 273
03300 273 ↔ 274 ↔ 275 ↔ 276 ↔ 277 ↔ 300 ↔ 301 ↔ 301
03400 302 ↔ 303 ↔ 304 ↔ 305 ↔ 306 ↔ 307 ↔ 310 ↔ 311
03500 312 ↔ 313 ↔ 314 ↔ 315 ↔ 317 ↔ 320 ↔ 322 ↔ 323
03600 325 ↔ 327 ↔ 331 ↔ 334 ↔ 340 ↔ 344 ↔ 351 ↔ 357
03700
03800 NMI ← START ;Reset??
03900 ;Interrupt vectors.
04000 LOC 177772
04100 NMI∧377
04200 (NMI⊗-10)∧377
04300 START∧377
04400 (START⊗-10)∧377
04500 TICK∧377
04600 (TICK⊗-10)∧377
04700 END